
#pragma once

// -----------------------------------------------------------------------------

#include "Win32.Diagnostics.Log.h"
#include "Win32.String.h"
#include "Win32.Types.h"
#include "Win32.MemoryObject.h"

namespace Kif
{
namespace Win32
{

static const TCHAR ErrorMessage_IndexOutOfBounds[] = _T("Index out of bound");

// -----------------------------------------------------------------------------
#pragma region // Declare MemoryDataItem class

enum MemoryParameterDirection
{
   MemoryParamDirection_Unknown = 0,
   MemoryParamDirection_ReturnValue = 1,
   MemoryParamDirection_Input = 2,
   MemoryParamDirection_Output = 3,
   MemoryParamDirection_InputOutput = 4
}  ;  // end of MemoryParameterDirection

class MemoryDataItem : public Kif::Win32::MemoryObject
{
private:
public:

   TCHAR *GetBuffer()
   { return((TCHAR*)getValue()); }

   void Fill(TCHAR fillChar)
   {
      TCHAR *b = (TCHAR*)getValue();
      int n = GetSize();
      int i;for(i=0;i<n;i++) *b=fillChar; b[n]=NULL;
   }
   void FillBlanks()
   {
      Fill(' ');
   }

   MemoryParameterDirection Direction;
   Kif::Win32::String ItemName;

   MemoryDataItem(
      Kif::Win32::String itemName, Kif::Win32::BaseType type,
         DWORD size, bool disposable) :
      Kif::Win32::MemoryObject(type,size,disposable)
   {
      Direction = MemoryParamDirection_Input;
      ItemName.Copy(itemName);
   }

   MemoryDataItem(
      Kif::Win32::String itemName, Kif::Win32::BaseType type) :
      Kif::Win32::MemoryObject(type)
   {
      Direction = MemoryParamDirection_Input;
      ItemName.Copy(itemName);
   }

   MemoryDataItem(
      TCHAR *itemName, Kif::Win32::BaseType type, DWORD size, bool disposable) :
      Kif::Win32::MemoryObject(type,size,disposable)
   {
      Direction = MemoryParamDirection_Input;
      ItemName.Copy(itemName);
   }

   MemoryDataItem(
      TCHAR *itemName, Kif::Win32::BaseType type) :
      Kif::Win32::MemoryObject(type,0,true)
   {
      Direction = MemoryParamDirection_Input;
      ItemName.Copy(itemName);
   }

   long cbBinaryData;
}  ;  // end of MemoryDataItem

// -----------------------------------------------------------------------------

class MemoryDataItemsCollection
{
private:
   MemoryDataItem **items;

public:

   MemoryDataItemsCollection()
   {
      Count = 0;
      items = NULL;
   }

  ~MemoryDataItemsCollection()
   {
      if (items)
      {
         DWORD i;
         for (i = 0; i < Count; i++)
            delete items[i];
         Kif::Win32::Memory::free(items);
      }
   }

   DWORD Count;

   /// <summary>add a parameter to the parameters list</summary>
   /// <param name="param">parameter to add</param>
   /// <returns>true is returned if the parameter was added</returns>
   MemoryDataItem *Add(MemoryDataItem *item)
   {
      if (item == NULL)
         return(NULL);

      // reallocate array
      MemoryDataItem **itms = (MemoryDataItem**)
         Kif::Win32::Memory::alloc(sizeof(MemoryDataItem**)*(Count+1));

      if (items != NULL)
      {
         DWORD c;
         for(c = 0 ; c < Count; c++)
            itms[c] = items[c];
         Kif::Win32::Memory::free(items);
      }

      items = itms;
      items[Count] = item;
      Count++;

      return(item);
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, bool value)
   {
      MemoryDataItem *i =
         new MemoryDataItem(itemName,Kif::Win32::BaseType_Boolean);
      i->setValue(value);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, short value)
   {
      MemoryDataItem *i = new MemoryDataItem(itemName,Kif::Win32::BaseType_Int16);
      i->setValue(value);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, int value)
   {
      MemoryDataItem *i = new MemoryDataItem(itemName,Kif::Win32::BaseType_Int32);
      i->setValue(value);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, long value)
   {
      MemoryDataItem *i = new MemoryDataItem(itemName,Kif::Win32::BaseType_Int32);
      i->setValue(value);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, Kif::Win32::DateTime *value)
   {
      MemoryDataItem *i = new MemoryDataItem(itemName,Kif::Win32::BaseType_DateTime);
      i->setValue(value);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, TCHAR *value, DWORD size)
   {
      MemoryDataItem *i =
         new MemoryDataItem(
            itemName,Kif::Win32::BaseType_WideString, size, true);
      i->setValue(value,size);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, Kif::Win32::String *value, DWORD size)
   {
      MemoryDataItem *i =
         new MemoryDataItem(
            itemName,Kif::Win32::BaseType_WideString, size, true);
      i->setValue(value->GetBuffer(),size);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, Kif::Win32::String &value, DWORD size)
   {
      return(Add(itemName,&value,size));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, char *value, DWORD size)
   {
      MemoryDataItem *i =
         new MemoryDataItem(
            itemName,Kif::Win32::BaseType_AnsiString, size, true);
      i->setValue(value,size);
      return(Add(i));
   }  // end of Add

   MemoryDataItem *AddAsAnsiString(TCHAR *itemName, TCHAR *value, DWORD size)
   {
      Kif::Win32::AnsiString str(value,size);
      return(Add(itemName,str.GetBuffer(),size));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, Kif::Win32::String &value)
   {
      MemoryDataItem *i =
         new MemoryDataItem(
            itemName,Kif::Win32::BaseType_WideString, (DWORD)value.GetLength(), true);
      i->setValue(value.GetBuffer(),(DWORD)value.GetLength());
      return(Add(i));
   }  // end of Add

   MemoryDataItem *Add(TCHAR *itemName, BYTE *value, DWORD size)
   {
      MemoryDataItem *i =
         new MemoryDataItem(
            itemName,Kif::Win32::BaseType_Blob, size, false);
      i->setValue(value,size);
      return(Add(i));
   }  // end of Add

   /// <summary>given an index return the parameter index</summary>
   /// <param name="itemIndex">item index to find</param>
   /// <returns>returns a pointer to the paramater at given index</returns>
   inline MemoryDataItem *getItem(DWORD itemIndex)
   {
      if ((itemIndex >= 0) && (itemIndex < Count))
         return(items[itemIndex]);
      return(NULL);
   }  // end of getItem

   inline long AsLong(DWORD itemIndex)
   {
      MemoryDataItem *i = getItem(itemIndex);
      if (i == NULL)
         throw ErrorMessage_IndexOutOfBounds;
      return(i->AsLong());
   }

   inline char* AsAnsiString(DWORD itemIndex)
   {
      MemoryDataItem *i = getItem(itemIndex);
      if (i == NULL)
         return(NULL);
      return(i->AsAnsiString());
   }

   inline wchar_t* AsWideString(DWORD itemIndex)
   {
      MemoryDataItem *i = getItem(itemIndex);
      if (i == NULL)
         return(NULL);
      return(i->AsWideString());
   }

}  ;  // end of MemoryDataItemsCollection

#pragma endregion
// -----------------------------------------------------------------------------

}
}
